#!/usr/bin/env python3
# -*- coding:utf-8 -*-

'''
文档Document类是其他所有文档类的抽象基类.Word,PDF类是Document的子类.

需求: 为Document子类提供打印能力
思路:
1. 在Document中提供print方法
'''
"""
class Document:
    def __init__(self,content):
        self.content = content

    def print(self):
        raise NotImplementedError()

class Word(Document): 
    pass
class Pdf(Document):
    pass
"""
'''
基类提供的方法不应该具体实现,因为它未必适合子类的打印,子类中需要覆盖重写.
print算是一种能力--打印功能,不是所有的Document的子类都需要的,所有,从这个角度出发,有点问题.
2. 需要打印的子类上增加
如果在现有子类上直接增加,违反了OCP的原则,所以应该继承后增加.
'''
"""
class Printable:
    def print(self):
        print(self.content)

class Document: # 第三方库,不允许修改.
    def __init__(self,content):
        self.content = content

class Word(Document):
    pass 

class Pdf(Document):
    pass

class PrintableWord(Printable,Word):
    pass
print(PrintableWord.__dict__)
print(PrintableWord.mro())

pw = PrintableWord('test string')
pw.print()
"""
'''
看似不错,如果需要还要提供其他能力,如何继承?
应用于网络,文档应该具备序列化的能力,类上就应该实现序列化.
可序列化还可能分为使用pickle,json,messagepack等.
这个时候发现,类可能太多了,继承的方式不是很好了.
功能太多,A类需要某几样功能,B类需要另几样功能,很繁琐.

3. 装饰器
   用装饰器增强一个类,把功能给类附加上去,那个类需要,就装饰它.
   优点: 简单方便,在需要的地方动态增加,直接使用装饰器.
'''
"""
def printable(cls):
    def _print(self):
        print(self.content,'装饰器')
    cls.print = _print
    return cls

class Document:
    def __init__(self,content):
        self.content = content
class Word(Document):
    pass
class Pdf(Document):
    pass

@printable  # 先继承,后装饰
class PrintableWord(Word):
    pass
print(PrintableWord.__dict__)
print(PrintableWord.mro())

pw = PrintableWord('test string')
pw.print()

@printable
class PrintablePdf(Word):
    pass
"""

'''
4. Mixin
'''
"""
class Document:
    def __init__(self,content):
        self.content = content

class Word(Document):
    pass
class Pdf(Document):
    pass

class PrintableMixin:
    def print(self):
        print(self.content,'Mixin')

class PrintableWord(PrintableMixin,Word):
    pass
print(PrintableWord.__dict__)
print(PrintableWord.mro())

def printable(cls):
    def _print(self):
        print(self.content,'装饰器')
    cls.print = _print
    return cls

@printable
class PrintablePdf(Word):
    pass
print(PrintablePdf.__dict__)
print(PrintablePdf.mro())
"""
'''
Mixin就是其它类混合进来,同时带来了类的属性和方法.
Mixin是类,就可以继承.
'''
"""
class Document:
    def __init__(self,content):
        self.content = content

class Word(Document):
    pass
class Pdf(Document):
    pass

class PrintableMixin:
    def print(self):
        print(self.content,'Mixin')

class PrintableWord(PrintableMixin,Word):
    pass
print(PrintableWord.__dict__)
print(PrintableWord.mro())

pw = PrintableWord('test string')
pw.print()

class SuperPrintableMixin(PrintableMixin):
    def print(self):
        print('~' * 20) # 打印增强
        super().print()
        print('~' * 20) # 打印增强
# PrintableMixin类的继承
class SuperPrintablePdf(SuperPrintableMixin,Pdf):
    pass

print(SuperPrintablePdf.__dict__)
print(SuperPrintablePdf.mro())

spp = SuperPrintablePdf('super print pdf')
spp.print()
"""


### 练习

# 1. Shape基类,要求所有子类都必须提供面积的计算,子类有三角形,矩形,圆.
import math

class Shape:
    @property
    def area(self):
        raise NotImplementedError('基类未实现')

class Triangle(Shape):
    def __init__(self,a,b,c):
        self.a = a
        self.b = b
        self.c = c

    @property
    def area(self):
        p = (self.a+self.b+self.c)/2
        return math.sqrt(p*(p-self.a)*(p-self.b)*(p-self.c))

class Rectangle(Shape):
    def __init__(self,width,height):
        self.width = width
        self.height = height
    
    @property
    def area(self):
        return self.width * self.height

class Circle(Shape):
    def __init__(self,radius):
        self.d = radius * 2
    
    @property
    def area(self):
        return math.pi * self.d * self.d * 0.25

shapes = [Triangle(3,4,5),Rectangle(3,4),Circle(4)]
for s in shapes:
    print('The area of {} = {}'.format(s.__class__.__name__,s.area))

'''
输出结果:
The area of Triangle = 6.0
The area of Rectangle = 12
The area of Circle = 50.26548245743669
'''

# 2. 圆类的数据可序列化.
import json
import msgpack 

class SerializableMixin:
    def dumps(self,t='json'):
        if t == 'json':
            return json.dumps(self.__dict__)
        elif t == 'msgpack':
            return msgpack.packb(self.__dict__)
        else:
            raise NotImplementedError('没有实现的序列化')

class SerializableCircleMixin(SerializableMixin,Circle):
    pass

scm = SerializableCircleMixin(4)
print(scm.area)
s = scm.dumps('msgpack')
print(s)

'''
输出结果为:
50.26548245743669
b'\x81\xa1d\x08'
'''